package com.iteaj.iot.plc.omron;

import com.iteaj.iot.FrameworkManager;
import com.iteaj.iot.SocketMessage;
import com.iteaj.iot.client.component.TcpClientComponent;
import com.iteaj.iot.codec.adapter.LengthFieldBasedFrameMessageDecoderAdapter;
import com.iteaj.iot.event.ClientStatus;
import com.iteaj.iot.event.StatusEvent;
import com.iteaj.iot.plc.PlcTcpClient;
import com.iteaj.iot.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.util.AttributeKey;

import java.nio.ByteOrder;

/**
 * 欧姆龙PLC基于tcp实现的客户端
 */
public class OmronTcpClient extends PlcTcpClient {

    private static AttributeKey<Boolean> handSingle = AttributeKey.newInstance("OMRON:HAND");

    // 握手信号报文
    private final byte[] handSingleMessage = new byte[] {
        0x46, 0x49, 0x4E, 0x53, // FINS
        0x00, 0x00, 0x00, 0x0C, // 后面的命令长度
        0x00, 0x00, 0x00, 0x00, // 命令码
        0x00, 0x00, 0x00, 0x00, // 错误码
        0x00, 0x00, 0x00, 0x00  // 节点号(为0将自动获取)
    };

    public OmronTcpClient(TcpClientComponent clientComponent, OmronConnectProperties config) {
        super(clientComponent, config);
        this.handSingleMessage[19] = config.getSA1();
    }

    @Override
    protected ChannelInboundHandler createProtocolDecoder() {
        return new LengthFieldBasedFrameMessageDecoderAdapter(ByteOrder.BIG_ENDIAN, 1024
                , 4, 4, 0, 0, true) {

            @Override
            public Class<? extends SocketMessage> getMessageClass() {
                return OmronMessage.class;
            }

            @Override
            public SocketMessage doTcpDecode(ChannelHandlerContext ctx, ByteBuf decode) {
                int readableBytes = (decode).readableBytes();
                byte[] message = new byte[readableBytes];
                (decode).readBytes(message).release();

                Boolean isHand = ctx.channel().attr(handSingle).get();
                // 先校验是否已经完成握手动作
                if(Boolean.TRUE.equals(isHand)) {
                    String channelId = ctx.channel().id().asShortText();
                    return new OmronMessage(message).setChannelId(channelId);
                } else {
                    // 修改连接状态为已握手
                    ctx.channel().attr(handSingle).set(true);

                    // 自动设置SA1
                    if(message.length >= 20) {
                        getConfig().setSA1(message[19]);
                    }

                    // 自动设置DA1
                    if(message.length >= 24) {
                        getConfig().setDA1(message[23]);
                    }

                    // 完成此次连接动作
                    OmronTcpClient.this.setSuccess();
                    // 发布客户端上线事件
                    FrameworkManager.publishEvent(new StatusEvent(OmronTcpClient.this, ClientStatus.online, getClientComponent()));
                    if(logger.isDebugEnabled()) {
                        logger.debug("PLC({}) 握手响应 - 状态：{} - 报文：{}"
                                , getName(), "成功", ByteUtil.bytesToHex(message));
                    }
                }

                return null;
            }
        };
    }

    @Override
    public void successCallback(ChannelFuture future) {
        // 发送PLC的握手报文
        future.channel().writeAndFlush(Unpooled.wrappedBuffer(handSingleMessage)).addListener(call -> {
            if(call.isSuccess()) {
                if(logger.isDebugEnabled()) {
                    logger.debug("PLC({}) 握手请求 - 状态：{} - 报文：{}"
                            , getName(), "成功", ByteUtil.bytesToHex(handSingleMessage));
                }
            } else {
                logger.error("PLC({}) 握手请求 - 状态：{} - 报文：{}"
                        , getName(), "失败", ByteUtil.bytesToHex(handSingleMessage));
            }
        });
    }

    @Override
    public OmronConnectProperties getConfig() {
        return (OmronConnectProperties) super.getConfig();
    }
}
